/*
 * monitorstream.h
 *
 *  Created on: Mar 15, 2012
 *      Author: yexijiang
 */

#ifndef MONITORSTREAM_H_
#define MONITORSTREAM_H_

#include <pthread.h>
#include <cstdio>
#include <iostream>
#include <map>
#include <list>
#include <utility>
#include "../common/common.h"

namespace event {

enum MonitorStreamType
{
	kCPU = 0,
	kMemory,
	kDisk,
};

/*
 * The basic observe node, each node contains the observed timestamp and the observed value.
 */
class ObserveNode
{
public:
	friend std::ostream& operator<<(std::ostream &out, ObserveNode &node);
	time_t timestamp;	//	the timestamp of the observed value
	float value;				//	the observed value
};

/*
 * The stream for observation, a stream contains a queue that contains the observed stream.
 * This stream is thread-safe.
 */
class MonitorStream
{
public:
	/*  Construct a new stream with given name, type, monitor rate, and sequence time range */
	MonitorStream(const std::string &name, MonitorStreamType type,
				  int monitor_rate, int range_in_second);
	/*  Get the name of stream */
	std::string GetStreamName() const;
	/*  Get the type of the stream */
	std::string GetStreamTypeName() const;
	/*  Get the monitor rate of the stream */
	float GetStreamRate() const;
	/*  Get the size of current sequence  */
	size_t Size();
	/*  Append a new observation to the sequence,
	 *  if the sequence is full in terms of time range,
	 *  remove the front one  */
	void Monitor();
	/*	Get a copy of current sequence
	 *	The reason that getting the copy instead of a reference to the sequence is to avoid the critical section.
	 */
	std::list<ObserveNode> GetCurSequence() const;

protected:
	/*	Parse the file that contains the system information	*/
	virtual void _ObtainNewObservation() = 0;

protected:
	std::string name_;
	MonitorStreamType type_;
	int monitor_rate_;
	int range_in_second_;
	std::list<ObserveNode> observe_sequence_;
	pthread_rwlock_t rw_mutex_;
};

/*
 * The manager of monitor streams.
 */
class StreamManager
{
public:
	/*
	 * Attach a new stream to the manager.
	 */
	static bool AttachStream(MonitorStream *stream);
	/*
	 * Get a specified stream.
	 */
	static const MonitorStream *GetStream(const std::string &stream_name);
	/*static void RunStreamsInThread();
	 * Start all the streams that are not started.
	 */
	static void RunStreamsInThread();

private:
	/*
	 * Run each stream as a thread.
	 */
	static void *_RunStreamInThread(void *stream);

private:
	static std::map<std::string, std::pair<pthread_t, MonitorStream*> > *streams_;
};

/*
 * The stream that monitor the CPU usage.
 */
class CPUMonitorStream : public MonitorStream
{
public:
	/*
	 * Construct a new stream to monitor
	 */
	CPUMonitorStream(const std::string &name, int cpu_index, int monitor_rate, int range_in_second);

public:
	/*	Parse the /proc/stat file to get the CPU information	*/
	virtual void _ObtainNewObservation();

private:
	static std::string stat_file;
	int cpu_index_;					//	The index of CPU, -1 represents the CPU in total
};

};

#endif /* MONITORSTREAM_H_ */
